package run
 
import (
	. "nightowl/config"
	. "nightowl/model"
	. "nightowl/common"
	"nightowl/svc/shell"
	"nightowl/logger"
	"nightowl/pool"
    "nightowl/download"    
	"fmt"
	"os"
	"strings"
    "gopkg.in/yaml.v2"
	"text/template"
	"path/filepath"
	"regexp"
	"sync"
	"github.com/pkg/errors"
	"time"
)
const(
	DELIVERY_STATUS_PENDING 			= "PENDING"
	DELIVERY_STATUS_DOWNLOADING 		= "DOWNLOADING"
	DELIVERY_STATUS_RENDERING 			= "RENDERING"
	DELIVERY_STATUS_RUNNING 			= "RUNNING"
	DELIVERY_STATUS_ERROR				= "ERROR"
	DELIVERY_STATUS_SUCCESS 			= "SUCCESS"
)
const (
	//step的启动脚本模版
	TASK_STEP_SHELL_ENTRYPOINT_TPL = "resources/stepEntrypoint.tpl"
	//hosts文件模版
	ANSI_HOST_TPL = "resources/hosts.tpl"
	//playbook文件模版
	ANSI_PLAYBOOK_TPL = "resources/playbook.yaml.tpl"

	//hosts文件名
	ANSI_HOST_FILE_NAME = "hosts"	
	//playbook文件名
	ANSI_PLAYBOOK_FILE_NAME = "playbook.yaml"
	//step脚本文件名
	TASK_STEP_ENTRYPOINT_FILE_NAME = "start.sh"

	//step文件引用目录
	FILE_REF_DIR = "files"
	//模版引用目录
	TPL_REF_DIR = "tpl"
	//库引用目录
	BIN_REF_DIR = "bin"
)
/**
 * 文件目录 tpl: 模版目录， build，文件渲染后的目录
 */
const(
	TPL_DIR_NAME = "tpl"
	BUILD_DIR_NAME = "build"
)
//解析文件变量
var RE_VAR_PATTERN = regexp.MustCompile(`(\$\{?((\w+\.)?\w+(\[\d\])?)\}?)`)
var TPL_FUNC_MAP template.FuncMap

/**
 * 
 * 初始化模版需要的函数
 */
func initTempFuncs(){
	TPL_FUNC_MAP = template.FuncMap{
		"Join" : strings.Join,
	    "default": func(value, defaultValue string) string {
		    if value == "" {
		        return defaultValue
		    }
		    return value
		},
	}
	// funcs.go 来源于 github, helm项目
	extra := funcMap()
	for k, v := range extra{
		TPL_FUNC_MAP[k] = v
	}
}
/**
 * 
 * 文件下载缓存管理 
 * 方案： 把所有连接都计入FileStorge，下载到Path位置，
 * 所有引用的地址都记录在Refs里，下载完后，会把文件copy到Refs里的每个路径里
 * 
 */
 type CacheFile struct{
 	Name string //文件名
 	Url string //文件url
 	Path string //实际存储路径
 	Refs []string //引用改文件的路径 
 }
/**
 * 
 * 
 */
type DeliveryRunner struct{
	Delivery Delivery
	Env WorkConfig
	Status string
	TaskType string
	TaskStopped bool
	threadPool pool.Pool
	TaskRuns []*TaskRun
	WorkEnv *WorkEnv
	rwMutex sync.RWMutex
	HostGroups map[string]*AnsiHostGroup
	HostParams map[string][]string
	CommonParams map[string]string
	downloader *download.DownloadManager
	FileStorage map[string]*CacheFile
}
var DeliveryRunSvc DeliveryRunner = DeliveryRunner{
	Status: DELIVERY_STATUS_PENDING,
	TaskType: "INSTALLATION",
}

func init() {
	initTempFuncs()
	DeliveryRunSvc.threadPool = *pool.New(5)
}
var shellRun shell.ShellRun = shell.ShellRun{}
func printTaskRuns[T any](obj T){
	// 将结构体转换为YAML
    y, err := yaml.Marshal(&obj)
    if err != nil {
        fmt.Printf("=====Marshal error: %v", err)
    }
    if y != nil {
         fmt.Printf("finished:", string(y))
    }
}
func parseTemplateString(tplString string, vars map[string]interface{}) string{
	m := RE_VAR_PATTERN.FindAllStringSubmatch(tplString, -1)
	result := tplString
    for _, items := range m{
    	oriStr := items[1]
    	k := items[2]
        v := vars[k]
        if v != nil {
        	result = strings.Replace(result, oriStr, v.(string), -1 )
        }
    }
    return result
}
func renderTemplate[T any](srcFilePath string, destFilePath string, vars map[string]T) error{
	destDir := filepath.Dir(destFilePath)
	err := os.MkdirAll(destDir, DEFAULT_FILE_MODE)
    if err != nil {
		logger.Error( fmt.Sprintf("renderTemplate|destDir:%s|err=%s\n", destDir, err) )
    	return err
    }
	destFile, err := os.Create(destFilePath)
	if err != nil {
		logger.Error( fmt.Sprintf("renderTemplate|render|srcFilePath:%s|destFilePath:%s|err=%s\n", srcFilePath, destFilePath, err) )
		return err
	}
	defer destFile.Close()
	temp := template.New(filepath.Base(srcFilePath)).Funcs(TPL_FUNC_MAP)
	temp, err = temp.ParseFiles(srcFilePath)
	if err != nil {
		logger.Error( fmt.Sprintf("renderTemplate|render|srcFilePath:%s|destFilePath:%s|err=%s\n", srcFilePath, destFilePath, err) )
		return err
	}
	temp.Execute(destFile, vars)
	return nil
}
/**
 * 任务启动
 */
func (dr *DeliveryRunner) Start(delivery *Delivery){	
	DeliveryRunSvc.Env = ENV_CONFIG.WorkConfig
	fmt.Printf("DeliveryRunSvc.Env:%s, %s\n", DeliveryRunSvc.Env, ENV_CONFIG, ENV_CONFIG.WorkConfig)
	if dr.Status == DELIVERY_STATUS_PENDING {
		dr.TaskStopped = false
		dr.Delivery = *delivery
		dr.WorkEnv = &WorkEnv{
			WorkDir: fmt.Sprintf("%s/delivery-%d", dr.Env.RootDir, dr.Delivery.Id),
		}
		dr.WorkEnv.TplDir = fmt.Sprintf("%s/%s", dr.WorkEnv.WorkDir, TPL_DIR_NAME)
		dr.WorkEnv.BuildDir = fmt.Sprintf("%s/%s", dr.WorkEnv.WorkDir, BUILD_DIR_NAME)

		dr.CommonParams = make(map[string]string)
		dr.HostGroups = make(map[string]*AnsiHostGroup)
		dr.HostParams = make(map[string][]string)
		dr.FileStorage = make(map[string]*CacheFile)
		logDir := fmt.Sprintf("%s/logs", dr.WorkEnv.BuildDir)
		err := os.MkdirAll(logDir, DEFAULT_FILE_MODE)
		if err != nil{
			logger.Error(fmt.Sprintf("Start|createLogDir|dir:%s|error:%s\n", logDir, err))
			return
		}
		shellRun.WorkDir = logDir
		printTaskRuns(dr.Env)


		dr.downloader = download.NewDownloadManager(3, func(d *download.DownloadManager, item *download.DownloadItem){
	        fmt.Printf( "item.Url:%s|msg:%s\n", item.Url, item.Msg)
	    },func(d *download.DownloadManager){
	        fmt.Printf( "Finished...\n")
	        dr.downloadFileCompleted()
	        dr.Status = DELIVERY_STATUS_RENDERING
	        dr.parseHostGroups()
			dr.renderTasks()
	        dr.Status = DELIVERY_STATUS_RUNNING
	        dr.renderHosts()
	        dr.renderPlaybooks()
	        dr.run()
	       
			// 将结构体转换为YAML
		    // y, err := yaml.Marshal(&dr.TaskRuns)
		    // if err != nil {
		    //     fmt.Printf("=====Marshal error: %v", err)
		    // }
		    // if y != nil {
		    //      fmt.Printf("finished:", string(y))
		    // }
	    })


		//No.1下载文档
		err = dr.prepareTasks()
		if err != nil{
			fmt.Printf("%s\n", err)
			return
		}
		dr.analyzeDependencies()
		dr.Status = DELIVERY_STATUS_DOWNLOADING
		dr.downloadFiles()
	}
}
const DEFAULT_FILE_MODE os.FileMode = 0777
/**
 * 根据deliveryTaskId获取delivery.task 
 */
func (dr *DeliveryRunner) getDeliveryTask(deliveryTaskId uint64) (*DeliveryTask){
	for _, task := range dr.Delivery.Tasks {
		if task.Id == deliveryTaskId {
			return &task
		}
	}
	return nil
}
/**
 * 根据deliveryStepId获取delivery.task.step
 */
func (dr *DeliveryRunner) getDeliveryStep(deliveryStepId uint64) (*DeliveryStep){
	for _, task := range dr.Delivery.Tasks {
		for _, steps := range task.Steps {
			for _, step := range steps{
				if step.Id == deliveryStepId {
					return &step
				}
			}
		}
	}
	return nil
}
/**
 * 根据libVerId获取LibVer
 */
func (dr *DeliveryRunner) getDeliveryLib(libVerId uint64) (*LibVer){
	for _, libVer := range dr.Delivery.Libs {
		if libVer.Id == libVerId{
			return &libVer
		}
	}
	return nil
}
func (dr *DeliveryRunner) GetStepRunById(deliveryStepId uint64)(* TaskStepRun){
	for _, taskRun := range dr.TaskRuns {
		for _, stepRun := range taskRun.StepRuns{
			if stepRun.DeliveryStepId == deliveryStepId{
				return stepRun
			}
		}
	}
	return nil
}
/**
 * No.1 准备文件,在执行机上，按task.id准备目录
 */
func (dr *DeliveryRunner) prepareTasks() error{
	logger.Info("prepareTasks...")
	dr.TaskRuns = make([]*TaskRun, len(dr.Delivery.Tasks))

	for i, task := range dr.Delivery.Tasks {
		taskRun := &TaskRun{
			Status: TASK_RUN_STATUS_PENDING,
			DeliveryTaskId: task.Id,
			TaskVerId: task.TaskVerId,
		}
		dr.TaskRuns[i] = taskRun
		taskType := dr.TaskType
		taskRun.StepRuns = make([]*TaskStepRun, len(task.Steps[taskType]))
		for j, step := range task.Steps[taskType]{			
			stepRun := &TaskStepRun{
				Status: TASK_RUN_STATUS_PENDING,
				StepId: step.TaskStepId,
				DeliveryStepId: step.Id,
			}
			taskRun.StepRuns[j] = stepRun
			stepRun.DirName = fmt.Sprintf("step-%d-%d", j, step.Id)
			stepRun.TplDir = fmt.Sprintf("%s/task-ver-%d/%s/%s", dr.WorkEnv.TplDir, task.TaskVerId, taskType, stepRun.DirName)
			stepRun.BuildDir = fmt.Sprintf("%s/task-ver-%d/%s/%s", dr.WorkEnv.BuildDir, task.TaskVerId, taskType, stepRun.DirName)
			stepRun.RemoteShellDir = fmt.Sprintf("%s/task-ver-%d/%s/%s", dr.Env.RemoteShellRootDir, task.TaskVerId, taskType,stepRun.DirName)
			stepLogDir := filepath.ToSlash( filepath.Dir(stepRun.BuildDir) )
			stepRun.LogFile = fmt.Sprintf("%s/log-%d-%d.log", stepLogDir, j, step.Id)
			
			if len(step.Snapshot.HostGroup) > 0 {
				stepRun.HostGroup = step.Snapshot.HostGroup
			}else{
				logger.Error("prepareTasks|task:%s|step:%s|miss host group", task.Ref.TaskRef.Title, step.Snapshot.Title)
				return errors.New("host group should't be nil")
			}

			err := os.MkdirAll(stepRun.TplDir, DEFAULT_FILE_MODE)
			if err != nil{
				logger.Error(fmt.Sprintf("prepareTasks|createDir|dir:%s|error:%s", stepRun.TplDir, err))
				return err
			}
			err = os.MkdirAll(stepRun.BuildDir, DEFAULT_FILE_MODE)
			if err != nil{
				logger.Error(fmt.Sprintf("prepareTasks|createDir|dir:%s|error:%s", stepRun.BuildDir, err))
				return err
			}
		}
	}
	return nil
}
func (dr *DeliveryRunner) analyzeDependencies(){
	logger.Info("analyzeDependencies...")
	findTaskRun := func(taskVerId uint64) *TaskRun{
		for _, taskRun := range dr.TaskRuns {
			if taskRun.TaskVerId == taskVerId {
				return taskRun
			}
		}
		return nil
	}
	for _, taskRun := range dr.TaskRuns {
		deliveryTask := dr.getDeliveryTask(taskRun.DeliveryTaskId)
		dependTaskVerIds := deliveryTask.DependTaskVerIds
		if dependTaskVerIds != nil {
			for _, taskVerId := range dependTaskVerIds{
				dependTaskRun := findTaskRun(taskVerId)
				if dependTaskRun != nil {
					taskRun.Dependencies = append(taskRun.Dependencies, dependTaskRun)
				}
			}
		}
	}
}

/**
 * 添加文件到Files，对下载的文件进行管理
 */
func (dr *DeliveryRunner) addCacheFile(name, url, destPath string){
	v := dr.FileStorage[url]
	if v == nil{
		v = &CacheFile{
			Name: name,
			Url: url,
			Path: destPath,
			Refs: []string{destPath},
		}
		dr.FileStorage[url] = v
	}
	v.Refs = append(v.Refs, destPath)
}
/**
 * 下载文件
 */
func (dr *DeliveryRunner) downloadFiles() error{
	logger.Info("downloadFiles...")

	addCacheFile := func(file DeployFile, fileDir string) error{
		if len(strings.TrimSpace(file.Url)) == 0 {
			return errors.New("url is empty")
		}
		//创建目录
		err := os.MkdirAll(fileDir, DEFAULT_FILE_MODE)
		if err != nil{
			logger.Error(fmt.Sprintf("downloadFiles|prepare|createDir|dir:%s|error:%s", fileDir, err))
			return err
		}
		// 文件绝对路径
		filePath := fmt.Sprintf("%s/%s", fileDir, file.Name)
		url := fmt.Sprintf("%s/%s", dr.Env.FileServer, file.Url)
		logger.Info(fmt.Sprintf("downloadFiles|prepare|fid:%d|url:%s|destPath=%s", file.Id, url, filePath))
		dr.addCacheFile(file.Name, url, filePath)

		return nil
	}
	for _, taskRun := range dr.TaskRuns {
		for _, stepRun := range taskRun.StepRuns{
			step := dr.getDeliveryStep(stepRun.DeliveryStepId)
			for _, taskFile := range step.Snapshot.Files{
				file := taskFile.Ref

				// 根据fileType判断使用哪个目录，tpl还是files
				refDir := TPL_REF_DIR
				if taskFile.FileType == FILE_TYPE_OTHER{
					refDir = FILE_REF_DIR
				}
				fileDir := fmt.Sprintf("%s/%s", stepRun.TplDir, refDir)
				addCacheFile(file, fileDir)
	    		// dr.downloader.Enqueue(f.Name, url, nil, filePath)
			}
			for _, dependLib := range step.Snapshot.DependLibs{
				libVer := dr.getDeliveryLib(dependLib.Id)
				fileDir := fmt.Sprintf("%s/%s", stepRun.BuildDir, BIN_REF_DIR)
				for _, file := range libVer.Files{
					addCacheFile(file, fileDir)
				}
				//cmd
				if len(libVer.Shell) > 0{
					cmdFp := fmt.Sprintf("%s/%s", fileDir, libVer.LibRef.Name)
					WriteFile(cmdFp, libVer.Shell, DEFAULT_FILE_MODE)
				}
			}
		}
	}
	for _, cacheFile := range dr.FileStorage{
		dr.downloader.Enqueue(cacheFile.Name, cacheFile.Url, nil, cacheFile.Path)
	}
	return nil
}
/**
 * 文件下载完执行
 */
func (dr *DeliveryRunner) downloadFileCompleted() error{
	for _, cacheFile := range dr.FileStorage{
		if !FileExists(cacheFile.Path){
			logger.Info("downloadFileCompleted|not exists|file:%s", cacheFile.Path)
			continue
		}
		for _, fp := range cacheFile.Refs{
			if !FileExists(fp){
				err := CopyFile(cacheFile.Path, fp)
				logger.Info("downloadFileCompleted|copy file error|src:%s|dst:%s|error:%s", cacheFile.Path, fp, err)
				return err
			}
		}
	}
	return nil
}
func (dr *DeliveryRunner) parseHostGroups() error{
	findHostGroup := func(groupName string) *DeliveryHostGroup{
		if len(groupName) == 0{
			return nil
		}
		for _, hostGroup := range dr.Delivery.HostGroups{
			if hostGroup.GroupName == groupName {
				return &hostGroup
			}
		}
		return nil
	}
	findHostUser := func(username string, host DeliveryHost) *DeliveryHostUser{
		if len(username) == 0{
			return nil
		}
		for _, user := range host.Users{
			if user.Username == username {
				return &user
			}
		}
		return nil
	}
	for _, deliveryHost := range dr.Delivery.Hosts {	
		newHost := &AnsiHost{
			Ipv4: deliveryHost.Ipv4,
			Port: deliveryHost.SshPort,
			User: &DeliveryHostUser{
				Username: deliveryHost.SshUsername,
				Pwd: deliveryHost.SshPwd,
			},
		}
		for _, groupName := range deliveryHost.Groups {		
			if _, hostGroup := dr.HostGroups[groupName]; !hostGroup {
				dr.HostGroups[groupName] = &AnsiHostGroup{
					Name: groupName,
				}
			}
			hostGroup := findHostGroup(groupName)
			if hostGroup != nil && len(hostGroup.SuUsername) > 0 && hostGroup.SuUsername != newHost.User.Username {
				suUser := &SuUser{
					Username: hostGroup.SuUsername,
					Method: hostGroup.SuMethod,
					Flags: hostGroup.SuFlags,
				}
				suHostUser := findHostUser(hostGroup.SuUsername, deliveryHost)
				if suHostUser != nil{
					suUser.Pwd = suHostUser.Pwd
				}
				newHost.SuUser = suUser
				dr.HostGroups[groupName].SuUser = suUser
			}
			dr.HostGroups[groupName].Hosts = append(dr.HostGroups[groupName].Hosts, newHost)
		}
	}
	//展开ip变量 eg: map["redis[0]"] = 10.0.0.1
	for k, grp := range dr.HostGroups{
		ips := make([]string, len(grp.Hosts))
		for i, host := range grp.Hosts{
			ips[i] = host.Ipv4
			commonParamKey := fmt.Sprintf("%s[%d]", k, i)
			dr.CommonParams[commonParamKey] = host.Ipv4
		}
		dr.HostParams[k] = ips
	}
	//设置taskRun SuUser
	for _, taskRun := range dr.TaskRuns {
		for _, stepRun := range taskRun.StepRuns{
			stepRun.SuUser = dr.HostGroups[stepRun.HostGroup].SuUser
		}
	}

	return nil
}
/**
 * 分析step变量
 * 返回map对象包含变量，和排序的变量key
 */
func (dr *DeliveryRunner) parseStepVars(deliveryStepId uint64) []*RunVar{
	varMap := make(map[string]interface{})
	stepVars := []*RunVar{}
	deliveryStep := dr.getDeliveryStep(deliveryStepId)
	//获取变量值
	varVal := func(key string) string{
		for _, v := range dr.Delivery.Vars {
			if v.Key == key {
				return v.Val
			}
		}
		return ""
	}
	for k, v := range dr.CommonParams{
		varMap[k] = v
	}
	for _, v := range dr.Delivery.Vars {
		varMap[v.Key] = v.Val
	}
	for _, v := range deliveryStep.Snapshot.Vars {
		val := varVal(v.Key)
		varMap[v.Key] = val
		stepVars = append( stepVars, &RunVar{ Key: v.Key, Val: val, } )
	}
	for _, stepVar := range stepVars{
		v2 := parseTemplateString( stepVar.Val.(string), varMap )
		varMap[stepVar.Key] = v2
		stepVar.Val = v2
	}
	return stepVars
}
/**
 * 渲染Task
 * 
 */
func (dr *DeliveryRunner) renderTasks() error{
	logger.Info("renderTasks...")
	var walkDir func(string, string, map[string]interface{}) error
	//遍历目录
	walkDir = func(srcPath string, destPath string, vars map[string]interface{}) error{
		entries, err := os.ReadDir(srcPath)
	    if err != nil {
	        return err
	    }
	    err = os.MkdirAll(destPath, DEFAULT_FILE_MODE)
        if err != nil {
			logger.Error( fmt.Sprintf("renderTasks|walkDir|destPath:%s|err=%s", destPath, err) )
        	return err
        }
	    for _, entry := range entries {
	        srcFilePath := filepath.Join(srcPath, entry.Name())
	        destFilePath := filepath.Join(destPath, entry.Name())
	        if entry.IsDir() {
	            // 递归调用listFiles处理子目录
	            err := os.MkdirAll(destFilePath, DEFAULT_FILE_MODE)
	            if err != nil {
					logger.Error( fmt.Sprintf("renderTasks|walkDir|srcFilePath:%s|destFilePath:%s|err=%s", srcFilePath, destFilePath, err) )
	            	return err
	            }
	            if err = walkDir(srcFilePath, destFilePath, vars); err != nil {
					logger.Error( fmt.Sprintf("renderTasks|walkDir|srcFilePath:%s|destFilePath:%s|err=%s", srcFilePath, destFilePath, err) )
	                return err
	            }
	        } else {
	            renderTemplate(srcFilePath, destFilePath, vars)
	        }
	    }
	    return nil
	}
	tplVars := func(stepVars []*RunVar) map[string]interface{}{
		varMap := make( map[string]interface{} )
		for _, stepVar := range stepVars{
			varMap[stepVar.Key] = stepVar.Val
		}
		return varMap
	}
	for _, taskRun := range dr.TaskRuns {
		for _, stepRun := range taskRun.StepRuns{
			stepVars := dr.parseStepVars(stepRun.DeliveryStepId)
			varMap := tplVars(stepVars)
			err := walkDir(stepRun.TplDir, stepRun.BuildDir, varMap)
			if err != nil{
				logger.Error( fmt.Sprintf("renderTasks|BuildDir:%s|err=%s", stepRun.BuildDir, err) )
				return err
			}
			deliveryStep := dr.getDeliveryStep(stepRun.DeliveryStepId)

			tplArgs := map[string]interface{}{
				"vars": stepVars,
				"hostParams": dr.HostParams,
				"cmd": deliveryStep.Snapshot.Cmd,
			}
			entrypointFilePath := fmt.Sprintf("%s/%s", stepRun.BuildDir, TASK_STEP_ENTRYPOINT_FILE_NAME)
			stepRun.Entrypoint = entrypointFilePath

			renderTemplate(TASK_STEP_SHELL_ENTRYPOINT_TPL, entrypointFilePath, tplArgs )
			
		}
	}
	return nil
}
/**
 * 渲染主机清单
 * 
 */
func (dr *DeliveryRunner) renderHosts() error{
	logger.Info("renderHosts...")
	hostGroups := dr.HostGroups
	dr.WorkEnv.HostFile = fmt.Sprintf("%s/%s", dr.WorkEnv.BuildDir, ANSI_HOST_FILE_NAME)
	renderTemplate(ANSI_HOST_TPL, dr.WorkEnv.HostFile, hostGroups)
	// for _, taskRun := range dr.TaskRuns{
	// 	taskRun.HostFile = hostFilePath
	// 	for _, stepRun := range taskRun.StepRuns{
	// 		stepRun.User = hostGroups[stepRun.HostGroup].User
	// 		stepRun.Become = hostGroups[stepRun.HostGroup].Become
	// 	}
	// }
	return nil
}
/**
 * 渲染Playbook
 * 
 */
func (dr *DeliveryRunner) renderPlaybooks() error{
	logger.Info("renderPlaybooks...")
	for _, taskRun := range dr.TaskRuns{
		var vars = make(map[string]interface{})
		vars["shellFile"] = TASK_STEP_ENTRYPOINT_FILE_NAME
		vars["remoteShellDir"] = dr.Env.RemoteShellRootDir
		vars["taskRun"] = taskRun
		for _, stepRun := range taskRun.StepRuns{
			deliveryStep := dr.getDeliveryStep(stepRun.DeliveryStepId)
			vars["stepRun"] = stepRun
			vars["snapshot"] = deliveryStep.Snapshot
			vars["hostGroup"] = deliveryStep.Snapshot.HostGroup
			stepRun.PlaybookDir = filepath.ToSlash( filepath.Dir(stepRun.BuildDir) )
			stepRun.PlaybookFile = fmt.Sprintf("%s/playbook-%s.yaml", stepRun.PlaybookDir, filepath.Base(stepRun.BuildDir))
			stepRun.RemoteShellFile = fmt.Sprintf("%s/%s", stepRun.RemoteShellDir, filepath.Base(stepRun.Entrypoint))

			renderTemplate( ANSI_PLAYBOOK_TPL, stepRun.PlaybookFile, vars)
		}
	}

	return nil
}
/**
 * 执行Task
 * 
 */
func (dr *DeliveryRunner) run() error{
	defer dr.checkAndRun()
	return nil
}
/**
 * 检查依赖并执行
 * 
 */
var i = 0
func (dr *DeliveryRunner) checkAndRun(){
	logger.Info("checkAndRun...")
	if dr.TaskStopped{
		return
	}
	dr.rwMutex.RLock() 
	defer dr.rwMutex.RUnlock()
	fmt.Printf("checkAndRun start-%d...\n", i)
	go func(){
		fmt.Printf("checkAndRun end-%d...\n", i)
		i = i + 1
	}()
	if dr.TaskStopped{
		return
	}
	for _, taskRun := range dr.TaskRuns{
		//依赖是否执行完
		ready := true
		for _, dependStepRun := range taskRun.Dependencies{
			if dependStepRun.Status != TASK_RUN_STATUS_SUCCESS{
				ready = false
			}
		}
		if ready{
			for _, stepRun := range taskRun.StepRuns{
				if stepRun.Status == TASK_RUN_STATUS_PENDING{
					go dr.runStep(stepRun, taskRun)
					return
				}
			}
		}
	}
	
}
/**
 * 检查所有的task状态
 * 
 */
func (dr *DeliveryRunner) checkRunStatus(){
	for _, taskRun := range dr.TaskRuns{
		if taskRun.Status != TASK_RUN_STATUS_SUCCESS{			
			return
		}
	}
	dr.Status = DELIVERY_STATUS_SUCCESS
	RunSyncSvc.UpdateStatus(dr.Delivery.Id, TASK_RUN_STATUS_SUCCESS)
}
func (dr *DeliveryRunner) checkTaskRunStatus(taskRun *TaskRun){
	for _, stepRun := range taskRun.StepRuns{
		if stepRun.Status != TASK_RUN_STATUS_SUCCESS{			
			return
		}
	}
	taskRun.Status = TASK_RUN_STATUS_SUCCESS
	RunSyncSvc.UpdateTaskStatus(taskRun.DeliveryTaskId, TASK_RUN_STATUS_SUCCESS)
	dr.checkRunStatus()
}
func (dr *DeliveryRunner) runStep(stepRun *TaskStepRun, taskRun *TaskRun){
	dr.rwMutex.Lock()	
	logger.Info("runStep...")
	defer dr.rwMutex.Unlock()
	stepRun.Status = TASK_RUN_STATUS_RUNNING
	taskRun.Status = TASK_RUN_STATUS_RUNNING
	RunSyncSvc.UpdateStepStatus(stepRun.DeliveryStepId, TASK_RUN_STATUS_RUNNING)
	RunSyncSvc.UpdateTaskStatus(taskRun.DeliveryTaskId, TASK_RUN_STATUS_RUNNING)
	cmd := fmt.Sprintf("cd %s; ansible-playbook -i %s %s -vv", dr.WorkEnv.BuildDir, ANSI_HOST_FILE_NAME, stepRun.PlaybookFile)
	fmt.Printf("runStep|cmd: %s\n", cmd)
	if stepRun.Logger == nil{
		stepRun.Logger = logger.New(stepRun.LogFile, logger.DEBUG)
	}
	//
	deliveryStep := dr.getDeliveryStep(stepRun.DeliveryStepId)
	stepRun.Logger.Debug("runStep|step: %s", deliveryStep.Snapshot.Title)
	stepRun.Logger.Debug("runStep|cmd: %s", cmd)
	// tag := fmt.Sprintf("%s", stepRun.DeliveryStepId)
	// err := shellRun.RunAsyncShell(cmd, nil, tag, func(tag , s string){
	// 	fmt.Printf("runStep|tag:%s|logs:%s",tag, s)
	// })
	stepRun.Status = TASK_RUN_STATUS_SUCCESS
	RunSyncSvc.UpdateStepStatus(stepRun.DeliveryStepId, TASK_RUN_STATUS_SUCCESS)
	dr.checkTaskRunStatus(taskRun)
	go dr.checkAndRun()
	fmt.Printf("runStep end...\n")
	go func(){
		i := 0
		for{
			if i >= 100{
				break
			}
			i = i + 1
			stepRun.Logger.Debug("stepId:%d|sleep 2 seconds...", stepRun.DeliveryStepId)
			time.Sleep(10 * time.Second)
		}
	}()
}
